from typing import Tuple
import sys
from .serializers import *
from . import request_type
from socket import socket
from .proto.utils import read
from struct import unpack


class Config:
    _config = {
        # 系统配置
        'system_config': [
            {"key": "配置修改标记", "byte_length": 1},
            {"key": "hardware_model", "byte_length": 17},
            {"key": "manufacture_tmie", "byte_length": 9},
            {"key": "hardware_version", "byte_length": 9},
            {"key": "software_version", "byte_length": 9},
            {"key": "device_serial_number", "byte_length": 33},
            {"key": "status", "byte_length": 1},
            {"key": "setting", "byte_length": 1},
            {"key": "mode", "byte_length": 1},
        ],
        'hardware_config': [
            {"key": "start", "byte_length": 1},
            {"key": "number_input_channle", "byte_length": 1},
            {"key": "mock_input_channle", "byte_length": 1},
            {"key": "number_output_channle", "byte_length": 1},
            {"key": "mock_output_channle", "byte_length": 1},
            {"key": "channle_485", "byte_length": 1},
        ],
        # 配置485
        '485_config': [
            {"key": "配置修改标记", "byte_length": 1},
            [
                {"key": "有效标志", "byte_length": 1},
                {"key": "line_number", "byte_length": 1},
                {"key": "br_number", "byte_length": 1},
                {"key": "check", "byte_length": 1},
                {"key": "copy_to_gprs", "byte_length": 1}
            ]
        ],
        # 本机网络配置
        'local_network_config': [
            {"key": "配置修改标记", "byte_length": 1},
            {"key": "ip_mode", "byte_length": 1},
            {"key": "ip_addr", "byte_length": 4},
            {"key": "mac", "byte_length": 7},
            {"key": "sub_network", "byte_length": 4},
            {"key": "gateway", "byte_length": 4},
            {"key": "dns1", "byte_length": 4},
            {"key": "dns2", "byte_length": 4},
        ],
        # 上传网络配置
        'upload_network_config': [
            {"key": "配置修改标记", "byte_length": 1},
            {"key": "token", "byte_length": 33},
            {"key": "heartbeat_interval", "byte_length": 2},
            {"key": "heartbeat_timeout", "byte_length": 2},
            {"key": "auto_upload", "byte_length": 1},
            {"key": "upload_interval", "byte_length": 2},
            {"key": "apn", "byte_length": 9},
            {"key": "apn_user", "byte_length": 17},
            {"key": "apn_password", "byte_length": 17},
            [
                {"key": "有效标志", "byte_length": 1},
                {"key": "服务器编号", "byte_length": 1},
                {"key": "服务器1~N是否启用", "byte_length": 1},
                {"key": "服务器1~NIP或域名", "byte_length": 33},
                {"key": "服务器1~N端口", "byte_length": 2}
            ]

        ],
        # 数据量输入配置
        'data_size_config': [
            {"key": "配置修改标记", "byte_length": 1},
            [
                {"key": "start", "byte_length": 1},
                {"key": "number", "byte_length": 1},
                {"key": "name", "byte_length": 10},
                {"key": "measuring", "byte_length": 1},
                {"key": "is_use", "byte_length": 1},
                {"key": "led_is_use", "byte_length": 1},
                {"key": "get_value_setting", "byte_length": 1},
            ]
        ],
        # 模拟量输入配置
        'mock_input_config': [
            {"key": "配置修改标记", "byte_length": 1},
            [
                {"key": "start", "byte_length": 1},
                {"key": "number", "byte_length": 1},
                {"key": "name", "byte_length": 17},
                {"key": "measuring", "byte_length": 1},
                {"key": "is_use", "byte_length": 1},
                {"key": "led_is_use", "byte_length": 1},
                {"key": "value_type", "byte_length": 1},
                {"key": "input_serial_number_a", "byte_length": 4},
                {"key": "input_serial_number_b", "byte_length": 4}
            ]
        ],
        # 传感器配置485
        'sensor_485_config': [
            {"key": "start", "byte_length": 1},
            [
                {"key": "start", "byte_length": 1},
                {"key": "input_number", "byte_length": 1},
                {"key": "name", "byte_length": 17},
                {"key": "measuring", "byte_length": 1},
                {"key": "status", "byte_length": 1},
                {"key": "led_status", "byte_length": 1},
                {"key": "addr_485", "byte_length": 4},
                {"key": "end_type", "byte_length": 1},
                {"key": "data_format", "byte_length": 1},
                {"key": "register_start", "byte_length": 2},
                {"key": "register_length", "byte_length": 1},
                {"key": "ratio_a", "byte_length": 4},
                {"key": "ratio_b", "byte_length": 4},
            ]
        ],
        # 数字量输出配置
        'number_output_config': [
            {"key": "start", "byte_length": 1},
            [
                {"key": "start", "byte_length": 1},
                {"key": "number", "byte_length": 1},
                {"key": "is_use", "byte_length": 1},
                {"key": "mode", "byte_length": 1},
                {"key": "default_value", "byte_length": 4},
            ]


        ],
        # 数字量组合输出配置
        'number_input_group_config': [
            {"key": "配置修改标记", "byte_length": 1},
            [
                {"key": "start", "byte_length": 1},
                {"key": "number", "byte_length": 1},
                {"key": "is_use", "byte_length": 1},
                {"key": "mode", "byte_length": 1},
                {"key": "group_mode", "byte_length": 1},
                {"key": "sub_device_1", "byte_length": 1},
                {"key": "sub_device_2", "byte_length": 1},
                {"key": "default_value", "byte_length": 4},
            ]

        ],
        # 模拟量输出配置
        'mock_output_config': [
            {"key": "配置修改标记", "byte_length": 1},
            [
                {"key": "start", "byte_length": 1},
                {"key": "number", "byte_length": 1},
                {"key": "is_use", "byte_length": 1},
                {"key": "mode", "byte_length": 1},
                {"key": "default_value", "byte_length": 4},
            ]
        ],
        # 自动规则配置
        'auto_rule_config': [
            {"key": "配置修改标记", "byte_length": 1},

            [
                {"key": "rule_code", "byte_length": 1},
                {"key": "rule_number", "byte_length": 1},
                {"key": "status", "byte_length": 1},
                {"key": "time_status", "byte_length": 1},
                {"key": "time_start", "byte_length": 6},
                {"key": "time_end", "byte_length": 6},
                {"key": "rule_status_1", "byte_length": 1},
                {"key": "rule_close_value_1", "byte_length": 1},
                {"key": "rule_input_type_1", "byte_length": 1},
                {"key": "rule_input_channel_1", "byte_length": 1},
                {"key": "rule_input_collection_1", "byte_length": 1},
                {"key": "rule_compare_1", "byte_length": 1},
                {"key": "rule_threshold_1", "byte_length": 4},
                {"key": "rule_float_1", "byte_length": 4},
                {"key": "rule_operation", "byte_length": 1},
                {"key": "rule_status_2", "byte_length": 1},
                {"key": "rule_close_value_2", "byte_length": 1},
                {"key": "rule_input_type_2", "byte_length": 1},
                {"key": "rule_input_channel_2", "byte_length": 1},
                {"key": "rule_input_collection_1", "byte_length": 1},
                {"key": "rule_compare_2", "byte_length": 1},
                {"key": "rule_threshold_2", "byte_length": 4},
                {"key": "rule_float_2", "byte_length": 4},
                {"key": "output_type", "byte_length": 1},
                {"key": "output_channle", "byte_length": 1},
                {"key": "output_value", "byte_length": 4},
            ]

        ],
        # 数据缓存配置
        'data_cache_config': [
            {"key": "配置修改标记", "byte_length": 1},
            {"key": "is_use", "byte_length": 1},
            {"key": "mode", "byte_length": 1},
            {"key": "save_interval", "byte_length": 2},
            {"key": "save_limit", "byte_length": 2},
            {"key": "last_write", "byte_length": 4},
            {"key": "last_read", "byte_length": 4},
        ],

    }

    _indexed = {}

    _config_type = {
        'sys': {
            'config_key': 'system_config',
            'code': b'\x00'
        },
        'hard': {
            'config_key': 'hardware_config',
            'code': b'\x01'
        },
        'line_485': {
            'config_key': '485_config',
            'code': b'\x02'
        },
        'local_network': {
            'config_key': 'local_network_config',
            'code': b'\x03'
        },
        'remote_network': {
            'config_key': 'upload_network_config',
            'code': b'\x04'
        },

        'number_input': {
            'config_key': 'data_size_config',
            'code': b'\x05'
        },
        'mock_input': {
            'config_key': 'mock_input_config',
            'code': b'\x06'
        },

        'sensor_485': {
            'config_key': 'sensor_485_config',
            'code': b'\x07'
        },
        'number_output': {
            'config_key': 'number_output_config',
            'code': b'\x08'
        },
        'number_group_output': {
            'config_key': 'number_input_group_config',
            'code': b'\x09'
        },
        'mock_output': {
            'config_key': 'mock_output_config',
            'code': b'\x0a'
        },
        'auto_rule': {
            'config_key': 'auto_rule_config',
            'code': b'\x0b'
        },
        'storage': {
            'config_key': 'data_cache_config',
            'code': b'\x0c'
        },

    }

    def __init__(self):
        for k in self._config:
            self._indexed[k] = [i['key']
                                for i in self._config[k] if isinstance(i, dict)]

    def get(self, item: str, key: str) -> Tuple:
        '''
        获取配置
        '''
        info = self._config_type[item]
        item = info['config_key']
        if item not in self._config:
            return None
        # 获取单个配置
        conf = self._config[item]
        # 生成单个配置下标方便计算offset_bytes
        indexed = self._indexed[item]
        try:
            # 寻找下标
            index = indexed.index(key)
        except ValueError:
            offset_length = 0
            for i in conf:

                if isinstance(i, list):
                    byte_length = sum((item['byte_length'] for item in i))
                    break
                else:
                    offset_length += i['byte_length']

        else:

            byte_length = conf[index]['byte_length']
            # 计算offset_bytes
            offset_length = sum((i['byte_length'] for i in conf[:index]))

        return byte_length, offset_length, int.from_bytes(info['code'], signed=True, byteorder=sys.byteorder)

    def get_sys_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 0},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )
        print(req.hex())
        conn.send(req)
        res = req.wait()
        res = unpackRegisterMessage.unpack(res[0][3:])

        return res

    def get_hard_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 1},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )

        conn.send(req)

        res = req.wait()

        res = HardwareSerializer.unpack(res[0][3:])

        return res

    def get_line_485__item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 2},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )

        conn.send(req)

        res = req.wait()
        res = [Setting_485.unpack(i[2:]) for i in res]
        result = []
        for i in res:
            result += i['settings']

        return {
            'settings': result
        }

    def get_local_network_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 3},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )

        conn.send(req)

        res = req.wait()
        res = LocalNetWorkSerializer.unpack(res[0][3:])

        return res

    def get_remote_network_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 4},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )

        conn.send(req)

        res = req.wait()
        res = RemoteNetworkSerializer.unpack(res[0][3:])

        return res

    def get_number_input_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 5},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )

        conn.send(req)
        
        res = req.wait()
        print(res)
        res = [NumberInputSetting.unpack(res[2:]) for i in res]
        result = []
        for i in res:
            result += i['settings']

        return {
            'settings': result
        }

    def get_mock_input_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 6},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )

        conn.send(req)
        res = req.wait()
        res = [MockInputSetting.unpack(i[2:]) for i in res]
        result = []

        for i in res:
            result += i['settings']

        return {
            'settings': result
        }

    def get_total_line_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 7},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )

        conn.send(req)
        res = req.wait()
        res = [SensorInputSerializer.unpack(i[3:]) for i in res]
        result = []
        for i in res:
            result += i['settings']

        return {
            'settings': result
        }

    def get_number_output_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 8},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )

        conn.send(req)
        res = req.wait()
        for i in res:
            print(i.hex(),'==============',len(i[3:]))
        res = [NumberOutPutSerializer.unpack(i[3:]) for i in res]
        result = []
        for i in res:
            print(i)
            result += i['settings']
        return {
            'settings': result
        }

    def get_number_group_output_item(self, conn: socket):

        req = readConfigPackagerItem.pack(
            {'item': 9},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )
        conn.send(req)

        res = req.wait()

        res = [NumberGroupOutPutSerializer.unpack(i[2:]) for i in res]
        result = []
        for i in res:
            result += i['settings']
        return {
            'settings': result
        }

    def get_mock_output_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 10},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )
        conn.send(req)
        res = req.wait()

        res = [MockOutPutSerializer.unpack(i[2:]) for i in res]
        result = []
        for i in res:
            result += i['settings']
        return {
            'settings': result
        }

    def get_auto_rule_item(self, conn: socket):
        pass

    def get_cache_item_item(self, conn: socket):
        req = readConfigPackagerItem.pack(
            {'item': 12},
            request_type.PAYLOAD_REQ_TO_MCU_GET_CLASS
        )

        conn.send(req)
        res = req.wait()

        res = [StorageSerializer.unpack(i[2:]) for i in res]
    
        return res[0]
